using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

namespace Universe.WCF.Behaviors
{
    public class TrafficBehavior : Attribute, IEndpointBehavior, IServiceBehavior
    {
        private TrafficStatisticConfiguration _configuration;

        public TrafficBehavior() : this(new TrafficStatisticConfiguration())
        {
        }

        public TrafficBehavior(TrafficStatisticConfiguration configuration)
        {
            _configuration = new TrafficStatisticConfiguration();
            _configuration.OnClient =
                delegate(string action, long requests, long recieved, long sent)
                    {
                        if (!ReferenceEquals(configuration, TrafficStatisticConfiguration.Common))
                            configuration.OnClient(action, requests, recieved, sent);

                        TrafficStatisticConfiguration.Common.OnClient(action, requests, recieved, sent);

                    };

            _configuration.OnServer =
                delegate(string action, long requests, long recieved, long sent)
                    {
                        if (!ReferenceEquals(configuration, TrafficStatisticConfiguration.Common))
                            configuration.OnServer(action, requests, recieved, sent);

                        TrafficStatisticConfiguration.Common.OnServer(action, requests, recieved, sent);
                    };

            TrafficPublisher.Publish();
        }

        public static void ApplyTo(ChannelFactory channelFactory, TrafficStatisticConfiguration.Handler onClient)
        {
            TrafficBehavior found = channelFactory.Endpoint.Behaviors.Find<TrafficBehavior>();
            if (found == null)
            {
                TrafficStatisticConfiguration tsc = new TrafficStatisticConfiguration(
                    onClient,
                    delegate { });

                TrafficBehavior tb = new TrafficBehavior(tsc);
                channelFactory.Endpoint.Behaviors.Add(tb);
            }
            else
            {
                found._configuration.OnClient += onClient;
            }
        }

        #region IEndpointBehavior Members

        void IEndpointBehavior.AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(new TrafficInspector(_configuration));
        }

        void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new TrafficInspector(_configuration));
        }

        void IEndpointBehavior.Validate(ServiceEndpoint endpoint)
        {
        }

        #endregion

        #region IServiceBehavior Members

        void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
        }

        void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher cDispatcher in serviceHostBase.ChannelDispatchers)
                foreach (EndpointDispatcher endpointDispatcher in cDispatcher.Endpoints)
                    endpointDispatcher.DispatchRuntime.MessageInspectors.Add(
                        new TrafficInspector(_configuration));
        }

        void IServiceBehavior.Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
        }

        #endregion
    }
}